/**
 * OCR相关工具函数
 */
import { createWorker } from "tesseract.js"
import type { RecognizeResult, Worker } from "tesseract.js"
import { applyMosaic } from "./mosaicUtils"
// 身份证号码正则表达式（18位，最后一位可能是X）
const ID_CARD_REGEX = /[1-9]\d{5}(18|19|20)\d{2}(0[1-9]|1[0-2])(0[1-9]|[12]\d|3[01])\d{3}(\d|X|x)/g
// 车牌号正则表达式（简化版本，仅匹配常见格式）
const LICENSE_PLATE_REGEX = /[京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领]{1}[A-Z]{1}[A-Z0-9]{5,6}/g
// 坐标框接口
interface Box {
    x0: number
    y0: number
    x1: number
    y1: number
}
/**
 * 初始化OCR Worker
 * @returns 初始化好的Tesseract Worker
 */
export const initOcrWorker = async (): Promise<Worker> => {
    const worker = await createWorker("chi_sim+eng")
    // 配置识别参数
    await worker.setParameters({
        tessedit_char_whitelist: "0123456789XABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz京津沪渝冀豫云辽黑湘皖鲁新苏浙赣鄂桂甘晋蒙陕吉闽贵粤青藏川宁琼使领",
    })
    return worker
}
/**
 * 识别并遮蔽身份证号码
 * @param canvas Canvas元素
 * @param ctx Canvas上下文
 * @param worker Tesseract Worker
 */
export const maskIdCardNumbers = async (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, worker: Worker): Promise<void> => {
    try {
        console.log("开始识别身份证号码...")
        // 识别文本
        const result = await worker.recognize(canvas)

        // 查找身份证号码
        const idCardMatches = result.data.text.match(ID_CARD_REGEX)
        console.log("找到身份证号码:", idCardMatches)
        if (idCardMatches && idCardMatches.length > 0) {
            // 获取每个识别到的身份证号码的位置
            for (const idCard of idCardMatches) {
                // 使用修改后的方法获取位置
                const boxes = getBoxesForText(canvas, result, idCard, "idcard")
                console.log("身份证号码位置:", boxes)

                // 应用马赛克到每个识别到的身份证号码区域
                boxes.forEach((box) => {
                    applyMosaic(
                        ctx,
                        box.x0 - 40,
                        box.y0 + 80,
                        box.x1 - box.x0 + 30,
                        box.y1 - box.y0 + 80,
                        5 // 使用更小的马赛克块，因为文字区域一般较小
                    )
                })
            }
        } else {
            // 如果未能识别到身份证号码，使用启发式方法估计位置
            console.log("未找到具体身份证号码，使用启发式方法")
            const estimatedBox = getEstimatedIdCardPosition(canvas)
            applyMosaic(ctx, estimatedBox.x0, estimatedBox.y0, estimatedBox.x1 - estimatedBox.x0, estimatedBox.y1 - estimatedBox.y0, 5)
        }
    } catch (error) {
        console.error("身份证号码识别失败:", error)
    }
}
/**
 * 识别并遮蔽车牌号
 * @param canvas Canvas元素
 * @param ctx Canvas上下文
 * @param worker Tesseract Worker
 */
export const maskLicensePlates = async (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, worker: Worker): Promise<void> => {
    try {
        console.log("开始识别车牌号...")
        // 识别文本
        const result = await worker.recognize(canvas)
        // 查找车牌号
        const licensePlateMatches = result.data.text.match(LICENSE_PLATE_REGEX)
        console.log("找到车牌号:", licensePlateMatches)
        if (licensePlateMatches && licensePlateMatches.length > 0) {
            // 获取每个识别到的车牌号的位置
            for (const plate of licensePlateMatches) {
                // 使用修改后的方法获取位置
                const boxes = getBoxesForText(canvas, result, plate, "plate")
                console.log("车牌号位置:", boxes)

                // 应用马赛克到每个识别到的车牌区域
                boxes.forEach((box) => {
                    applyMosaic(ctx, box.x0, box.y0, box.x1 - box.x0, box.y1 - box.y0, 5)
                })
            }
        }
    } catch (error) {
        console.error("车牌号识别失败:", error)
    }
}
/**
 * 获取文本在图像中的位置
 * 使用修改后的方法，不依赖data.width和data.height
 * @param canvas Canvas元素
 * @param result OCR识别结果
 * @param text 要查找的文本
 * @param type 文本类型 (idcard或plate)
 * @returns 找到的区域坐标数组
 */
function getBoxesForText(canvas: HTMLCanvasElement, result: RecognizeResult, text: string, type: "idcard" | "plate"): Box[] {
    const boxes: Box[] = []
    console.log("寻找文本:", text, "类型:", type)

    try {
        // 使用canvas尺寸而不是OCR结果
        const canvasWidth = canvas.width
        const canvasHeight = canvas.height
        console.log("Canvas尺寸:", canvasWidth, canvasHeight)

        // 尝试查找文本在OCR结果中的位置
        const words = (result.data as any).words || []

        // 尝试使用单词匹配
        if (words && words.length > 0) {
            console.log("检查OCR单词列表...", words.length)
            for (const word of words) {
                if (word.text && word.text.includes(text) && word.bbox) {
                    console.log("找到匹配的单词:", word.text)
                    const box: Box = {
                        x0: Math.max(0, word.bbox.x0 - 5),
                        y0: Math.max(0, word.bbox.y0 - 5),
                        x1: Math.min(canvasWidth, (word.bbox.x1 || 0) + 5),
                        y1: Math.min(canvasHeight, (word.bbox.y1 || 0) + 5),
                    }
                    boxes.push(box)
                    break // 找到第一个匹配就退出
                }
            }
        }

        // 如果未找到，尝试使用行匹配
        if (boxes.length === 0) {
            const lines = (result.data as any).lines || []
            console.log("检查OCR行列表...", lines.length)

            if (lines && lines.length > 0) {
                for (const line of lines) {
                    if (line.text && line.text.includes(text) && line.bbox) {
                        console.log("找到匹配的行:", line.text)
                        const box: Box = {
                            x0: Math.max(0, line.bbox.x0 - 5),
                            y0: Math.max(0, line.bbox.y0 - 5),
                            x1: Math.min(canvasWidth, (line.bbox.x1 || 0) + 5),
                            y1: Math.min(canvasHeight, (line.bbox.y1 || 0) + 5),
                        }
                        boxes.push(box)
                        break // 找到第一个匹配就退出
                    }
                }
            }
        }

        // 如果仍未找到，使用估计位置
        if (boxes.length === 0) {
            console.log("使用估计位置")
            let box: Box

            if (type === "idcard") {
                box = getEstimatedIdCardPosition(canvas)
            } else {
                box = getEstimatedLicensePlatePosition(canvas)
            }

            boxes.push(box)
        }
    } catch (error) {
        console.error("获取文本位置出错:", error)
        // 出错时使用估计位置
        if (type === "idcard") {
            boxes.push(getEstimatedIdCardPosition(canvas))
        } else {
            boxes.push(getEstimatedLicensePlatePosition(canvas))
        }
    }

    return boxes
}
/**
 * 估计身份证号码在图像中的位置
 * @param canvas Canvas元素
 * @returns 估计的区域坐标
 */
function getEstimatedIdCardPosition(canvas: HTMLCanvasElement): Box {
    const width = canvas.width
    const height = canvas.height

    // 身份证号码通常位于身份证的下半部分
    return {
        x0: width * 0.4,
        y0: height * 0.65,
        x1: width * 0.9,
        y1: height * 0.8,
    }
}
/**
 * 估计车牌号在图像中的位置
 * @param canvas Canvas元素
 * @returns 估计的区域坐标
 */
function getEstimatedLicensePlatePosition(canvas: HTMLCanvasElement): Box {
    const width = canvas.width
    const height = canvas.height

    // 车牌号通常位于车辆的中下部位置
    return {
        x0: width * 0.3,
        y0: height * 0.4,
        x1: width * 0.7,
        y1: height * 0.6,
    }
}
/**
 * 一次性处理所有敏感文本（身份证号和车牌号）
 * @param canvas Canvas元素
 * @param ctx Canvas上下文
 */
export const maskAllSensitiveText = async (canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D): Promise<void> => {
    try {
        console.log("开始处理所有敏感文本...")
        const worker = await initOcrWorker()
        console.log("OCR Worker初始化完成")

        // 识别并遮蔽身份证号
        await maskIdCardNumbers(canvas, ctx, worker)

        // 识别并遮蔽车牌号
        await maskLicensePlates(canvas, ctx, worker)

        // 释放worker
        await worker.terminate()
        console.log("OCR处理完成，Worker已释放")
    } catch (error) {
        console.error("敏感文本识别失败:", error)
    }
}
